package com.pvdnc.riru.system_server;

import android.annotation.SuppressLint;
import android.os.IBinder;
import android.util.Log;

import com.pvdnc.riru.MethodUtils;
import com.pvdnc.riru.UserUtils;
import com.pvdnc.riru.common.ServiceObserver;
import com.pvdnc.riru.system_server.filter.PackageFilterManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

import andhook.lib.xposed.XC_MethodHook;
import andhook.lib.xposed.XposedBridge;

@SuppressLint("PrivateApi")
public class HookNetworkStatService extends ServiceObserver {
    private static final String TAG=HookNetworkStatService.class.getSimpleName();

    public static final HookNetworkStatService INSTANCE=new HookNetworkStatService();

    @Override
    public void onServiceAdd(String name, IBinder service) {
        Class<?> serviceClass=service.getClass();
        Log.d(TAG,"service class:"+serviceClass);
        ClassLoader cl=serviceClass.getClassLoader();
        try {
            Objects.requireNonNull(cl);
             hookRecordData(cl);
             hookRecordHistory(cl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static final boolean BLOCK_ALL_RECORD=false;

    private boolean shouldBlock(int uid){
        if(BLOCK_ALL_RECORD)
            return true;
        if(!UserUtils.isUserUid(uid))
            return true;
        //按包名过滤
        String pkgName=PMSUtils.get().getPackageNameForUid(uid);
        if(PackageFilterManager.INSTANCE.callFilter(pkgName)){
            return true;
        }
        return false;
    }

    private void hookRecordData(ClassLoader cl) throws Exception {
        Class<?> nscClass= cl.loadClass("com.android.server.net.NetworkStatsCollection");
        Log.d(TAG,"nscClass:"+nscClass);
        Method recordData = MethodUtils.getMethodByName(nscClass,"recordData").get(0);
        XposedBridge.hookMethod(recordData, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                Log.d(TAG, "invoked before hooked recordData");
                try {
                    int uid=(int)param.args[1];
                    Log.d(TAG,"[RecordData] current NSS uid:"+ uid);
                    if(!shouldBlock(uid))
                        return;
                    //跳过调用
                    Log.d(TAG, "[RecordData] attempt to intercept NSS uid:" + uid);
                    param.setResult(null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        Log.d(TAG,"finish hooking recordData");
    }

    private void hookRecordHistory(final ClassLoader cl) throws Exception {
        Class<?> nscClass= cl.loadClass("com.android.server.net.NetworkStatsCollection");
        Log.d(TAG,"nscClass:"+nscClass);
        Method recordHistory=MethodUtils.getMethodByName(nscClass,"recordHistory").get(0);
        XposedBridge.hookMethod(recordHistory,new XC_MethodHook(){
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                Log.d(TAG, "invoked before hooked recordHistory");
                try {
                    Class<?> keyClass=cl.loadClass("com.android.server.net.NetworkStatsCollection$Key");
                    Field uidField=keyClass.getDeclaredField("uid");
                    uidField.setAccessible(true);
                    int uid=uidField.getInt(param.args[0]);
                    Log.d(TAG,"[RecordHistory] current NSS uid is:"+ uid);
                    if(!shouldBlock(uid))
                        return;
                    //跳过调用
                    Log.d(TAG,"[RecordHistory] attempt to intercept NSS uid:"+ uid);
                    param.setResult(null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        Log.d(TAG,"finish hooking recordHistory");
    }
}
